package com.liliudong.template.biz.service.sys.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import com.liliudong.template.biz.mapper.sys.SysDeptMapper;
import com.liliudong.template.biz.service.sys.SysDeptService;
import com.liliudong.template.biz.service.sys.SysRoleDeptService;
import com.liliudong.template.common.constant.ExMessage;
import com.liliudong.template.common.convert.sys.SysDeptConvert;
import com.liliudong.template.common.request.sys.SysDeptAddRequest;
import com.liliudong.template.common.request.sys.SysDeptModifyRequest;
import com.liliudong.template.common.request.sys.SysDeptPageRequest;
import com.liliudong.template.common.entity.BaseEntity;
import com.liliudong.template.common.entity.sys.SysDept;
import com.liliudong.template.common.exception.BizException;
import com.liliudong.template.common.response.sys.SysDeptDetailResponse;
import com.liliudong.template.common.response.sys.SysDeptPageResponse;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

import static com.liliudong.template.common.entity.sys.table.SysDeptTableDef.SYS_DEPT;

/**
 * 服务实现
 *
 * @author liudo
 * @date 2024-08-01 19:44:49
 */
@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept>
        implements SysDeptService {

    private static final String FIRST_DEPT_NO = "01";
    private static final String TWO_DIGIT_FORMAT = "%02d";

    private final SysRoleDeptService sysRoleDeptService;

    @Override
    public void addOne(SysDeptAddRequest sysDeptAddRequest) {
        SysDept sysDept = SysDeptConvert.INSTANCE.addDTO2Entity(sysDeptAddRequest);
        // 相同部门部门下不能部门不能重名
        this.checkName(sysDept.getName(), sysDept.getParentId());
        // 自动生成部门编号 父编号 + 序列
        Long parentId = sysDept.getParentId();
        String nextDeptNo = generateNextDeptNo(parentId);
        sysDept.setDeptNo(nextDeptNo);
        this.save(sysDept);
    }

    @Override
    public void deleteById(Long id) {
        long count = sysRoleDeptService.countByDeptId(id);
        if (count > 0) {
            throw new BizException(ExMessage.DEPT_UNION_ROLE);
        }
        removeById(id);
    }

    @Override
    public void modifyById(Long id, SysDeptModifyRequest sysDeptModifyRequest) {
        // 相同部门下部门不能重名
        checkName(sysDeptModifyRequest.getName(), sysDeptModifyRequest.getParentId());
        SysDept sysDept = SysDeptConvert.INSTANCE.modifyDTO2Entity(sysDeptModifyRequest);
        sysDept.setId(id);
        this.updateById(sysDept);
    }

    @Override
    public SysDeptDetailResponse detailById(Long id) {
        return this.getOneAs(QueryWrapper.create().where(SYS_DEPT.ID.eq(id)), SysDeptDetailResponse.class);
    }

    @Override
    public Page<SysDeptPageResponse> queryPage(Long page, Long size, SysDeptPageRequest sysDeptPageRequest) {
        return queryChain().pageAs(Page.of(page, size), SysDeptPageResponse.class);
    }

    @Override
    public List<Tree<Long>> queryTree() {
        List<SysDept> sysDeptList = list();
        return TreeUtil.build(sysDeptList, 0L, (sysDept, tree) -> {
            String deptNo = sysDept.getDeptNo();
            String name = sysDept.getName();
            Long parentId = sysDept.getParentId();
            Long id = sysDept.getId();
            LocalDateTime createdAt = sysDept.getCreatedAt();
            LocalDateTime updatedAt = sysDept.getUpdatedAt();

            tree.setId(id);
            tree.setParentId(parentId);
            tree.setName(name);
            tree.putExtra(SysDept.Fields.deptNo, deptNo);
            tree.putExtra(BaseEntity.Fields.createdAt, createdAt);
            tree.putExtra(BaseEntity.Fields.updatedAt, updatedAt);
        });
    }

    /**
     * 检查名称
     *
     * @param name     名称
     * @param parentId 父id
     */
    private void checkName(String name, Long parentId) {
        boolean exists = queryChain()
                .where(SYS_DEPT.NAME.eq(name).and(SYS_DEPT.PARENT_ID.eq(parentId)))
                .exists();
        if (exists) {
            throw new BizException(ExMessage.DEPT_NAME_REPEAT);
        }
    }

    /**
     * 生成下一个部门编号
     *
     * @param parentId 父id
     * @return {@link String }
     */
    private String generateNextDeptNo(Long parentId) {
        SysDept sysDeptLatest = queryChain()
                .select(SYS_DEPT.DEPT_NO)
                .where(SYS_DEPT.PARENT_ID.eq(parentId))
                .orderBy(SYS_DEPT.CREATED_AT.desc())
                .limit(1)
                .one();
        if (Objects.isNull(sysDeptLatest)) {
            SysDept sysDeptParent = getById(parentId);
            String parentDeptNo = sysDeptParent.getDeptNo();
            return parentDeptNo + FIRST_DEPT_NO;
        }
        String latestDeptNo = sysDeptLatest.getDeptNo();
        String parentDeptNo = latestDeptNo.substring(0, latestDeptNo.length() - 2);
        String sequence = latestDeptNo.length() == 2 ? latestDeptNo : latestDeptNo.substring(latestDeptNo.length() - 2);
        return parentDeptNo + String.format(TWO_DIGIT_FORMAT, Integer.parseInt(sequence) + 1);
    }
}
